import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import json
import os
import datetime
import pandas as pd
from plyer import notification
import winsound
import threading
import time


PRIORITY_LEVELS = ["高", "中", "低"]
TAG_CATEGORIES = ["工作", "生活", "学习", "其他"]


class Task:
    def __init__(self, content, priority="中", tag="其他", created_at=None):
        self.content = content
        self.priority = priority
        self.tag = tag
        self.created_at = created_at or datetime.datetime.now().strftime("%Y-%m-%d")
        self.started_at = None
        self.done_at = None
        self.reminder_time = None
        self.daily_reminder = False
        self.reminder_active = True
        self.sound_path = None
        self.notes = ""  # 新增备注字段

    def to_dict(self):
        return {
            "内容": self.content,
            "优先级": self.priority,
            "分类": self.tag,
            "创建时间": self.created_at,
            "开始时间": self.started_at,
            "完成时间": self.done_at,
            "提醒时间": self.reminder_time,
            "每日提醒": self.daily_reminder,
            "提醒状态": self.reminder_active,
            "声音路径": self.sound_path,
            "备注": self.notes  # 新增备注保存
        }

    @classmethod
    def from_dict(cls, data):
        task = cls(
            data["内容"],
            data["优先级"],
            data["分类"],
            data["创建时间"]
        )
        task.started_at = data.get("开始时间")
        task.done_at = data.get("完成时间")
        task.reminder_time = data.get("提醒时间")
        task.daily_reminder = data.get("每日提醒", False)
        task.reminder_active = data.get("提醒状态", True)
        task.sound_path = data.get("声音路径")
        task.notes = data.get("备注", "")  # 新增备注加载
        return task


class TodoApp:
    def __init__(self, root):
        self.root = root
        self.root.title("TickTick")
        self.root.geometry("1200x700")
        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(0, weight=1)

        # 自定义样式
        self.style = ttk.Style()
        self.style.theme_use('clam')

        # 全局字体设置
        default_font = ("Microsoft YaHei", 10)  # 使用微软雅黑字体
        self.root.option_add("*Font", default_font)

        # 按钮样式 - 修改字体大小
        self.style.configure("TButton",
                             padding=6,
                             relief="flat",
                             background="#26A69A",
                             foreground="white",
                             font=("Microsoft YaHei", 11),  # 增大字体到11
                             borderwidth=0)
        
        # Treeview 样式 - 增大行高和字体
        self.style.configure("Todo.Treeview", 
                            rowheight=30, 
                            fieldbackground="#e3f2fd",
                            font=("Microsoft YaHei", 10))  # 增大字体
        self.style.configure("Doing.Treeview", 
                            rowheight=30, 
                            fieldbackground="#fffde7",
                            font=("Microsoft YaHei", 10))  # 增大字体
        self.style.configure("Done.Treeview", 
                            rowheight=30, 
                            fieldbackground="#e8f5e9",
                            font=("Microsoft YaHei", 10))  # 增大字体

        # 标签框架样式
        self.style.configure("TLabelFrame", 
                           font=("Microsoft YaHei", 12, "bold"))  # 增大标题字体

        # 数据初始化
        self.todo_items = []
        self.doing_items = []
        self.done_items = []

        # 加载历史任务
        self.load_tasks()

        # 创建界面组件
        self.create_menu()
        self.create_widgets()

        # 启动定时检查提醒
        self.check_reminders()

        self.buzzer_active = False  # 在__init__中添加这行
        self.buzzer_thread = None  # 蜂鸣器线程

        # 绑定右键菜单事件
        self.todo_tree.bind("<Button-3>", self.show_context_menu)
        self.doing_tree.bind("<Button-3>", self.show_context_menu)
        self.done_tree.bind("<Button-3>", self.show_context_menu)

    def create_menu(self):
        """创建顶部菜单栏"""
        menubar = tk.Menu(self.root)

        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="导入Excel", command=self.import_from_excel)  # 新增导入功能
        file_menu.add_command(label="导出Excel", command=self.export_to_excel)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        menubar.add_cascade(label="文件", menu=file_menu)

        # 配置菜单
        config_menu = tk.Menu(menubar, tearoff=0)
        config_menu.add_command(label="管理分类", command=self.manage_tags)
        menubar.add_cascade(label="配置", menu=config_menu)

        # 帮助菜单
        help_menu = tk.Menu(menubar, tearoff=0)
        help_menu.add_command(label="使用指南", command=self.show_guide)  # 新增使用指南菜单项
        help_menu.add_command(label="关于", command=self.show_about)
        menubar.add_cascade(label="帮助", menu=help_menu)

        self.root.config(menu=menubar)

    def create_widgets(self):
        # 输入区域 - 修改输入框字体
        input_frame = ttk.Frame(self.root)
        input_frame.grid(row=0, column=0, columnspan=3, pady=10, padx=10, sticky="ew")
        
        # 输入框 - 使用更大的字体
        self.task_entry = ttk.Entry(input_frame, font=("Microsoft YaHei", 12), width=40)
        self.task_entry.grid(row=0, column=0, padx=5, sticky="ew")
        
        # 分类选择框 - 调整字体
        self.category_var = tk.StringVar(value="工作")
        category_menu = ttk.Combobox(
            input_frame,
            textvariable=self.category_var,
            values=TAG_CATEGORIES,
            state="readonly",
            width=8,
            font=("Microsoft YaHei", 11),  # 增大字体
            style="TCombobox"
        )
        category_menu.grid(row=0, column=1, padx=5)
        
        # 添加按钮 - 使用更醒目的样式
        add_button = ttk.Button(
            input_frame, 
            text="添加事务",
            style="Accent.TButton",
            command=lambda: self.add_task(category=self.category_var.get())
        )
        add_button.grid(row=0, column=2, padx=5)
        
        # 添加默认提示文本
        self.task_entry.insert(0, "在此输入事务")
        self.task_entry.bind("<FocusIn>", self.on_entry_click)
        self.task_entry.bind("<FocusOut>", self.on_focus_out)

        # 在样式设置部分添加按钮样式(在__init__方法中)
        self.style.configure("Accent.TButton",
                           padding=8,
                           background="#4CAF50",
                           foreground="white",
                           font=("Arial", 10, "bold"))
        self.style.map("Accent.TButton",
                      background=[('pressed', '#388E3C'), ('active', '#66BB6A')])

        # 表格化任务展示
        columns_todo = ("序号", "内容", "分类", "创建时间")  # 添加分类列
        columns_doing = ("序号", "内容", "分类", "开始时间")  # 添加分类列
        columns_done = ("序号", "内容", "分类", "完成时间")  # 添加分类列

        # 计算布局参数
        frame_width = 380  # 总宽度1200px，三个列表各占约380px
        padding = (1200 - 3 * frame_width) // 4  # 计算两侧的填充间距

        # Todo 列表容器
        todo_container = ttk.Frame(self.root)
        todo_container.grid(row=1, column=0, padx=padding, sticky="nsew")
        self.root.grid_columnconfigure(0, weight=1)

        # Doing 列表容器
        doing_container = ttk.Frame(self.root)
        doing_container.grid(row=1, column=1, padx=padding, sticky="nsew")
        self.root.grid_columnconfigure(1, weight=1)

        # Done 列表容器
        done_container = ttk.Frame(self.root)
        done_container.grid(row=1, column=2, padx=padding, sticky="nsew")
        self.root.grid_columnconfigure(2, weight=1)

        # Todo 列表
        todo_frame = ttk.LabelFrame(todo_container, text="Todo 待办", labelanchor="n")
        todo_frame.pack(fill="both", expand=True)

        self.todo_tree = ttk.Treeview(todo_frame, show='headings', style="Todo.Treeview")
        self.setup_tree_columns(self.todo_tree, columns_todo)
        self.todo_tree.pack(fill="both", expand=True, padx=5, pady=5)
        # 绑定双击事件
        self.todo_tree.bind("<Double-1>", lambda e: self.set_reminder())

        todo_button_frame = ttk.Frame(todo_frame)
        todo_button_frame.pack(pady=5)

        start_button = ttk.Button(todo_button_frame, text="▶️ 开始", command=self.move_to_doing)
        start_button.pack(side=tk.LEFT, padx=5)

        delete_todo_button = ttk.Button(todo_button_frame, text="🗑️ 删除",
                                        command=lambda: self.delete_item(self.todo_tree, self.todo_items))
        delete_todo_button.pack(side=tk.LEFT, padx=5)

        # Doing 列表
        doing_frame = ttk.LabelFrame(doing_container, text="Doing 进行中", labelanchor="n")
        doing_frame.pack(fill="both", expand=True)

        self.doing_tree = ttk.Treeview(doing_frame, show='headings', style="Doing.Treeview")
        self.setup_tree_columns(self.doing_tree, columns_doing)
        self.doing_tree.pack(fill="both", expand=True, padx=5, pady=5)

        doing_button_frame = ttk.Frame(doing_frame)
        doing_button_frame.pack(pady=5)

        finish_button = ttk.Button(doing_button_frame, text="✅ 完成", command=self.move_to_done)
        finish_button.pack(side=tk.LEFT, padx=5)

        delete_doing_button = ttk.Button(doing_button_frame, text="🗑️ 删除",
                                         command=lambda: self.delete_item(self.doing_tree, self.doing_items))
        delete_doing_button.pack(side=tk.LEFT, padx=5)

        # Done 列表
        done_frame = ttk.LabelFrame(done_container, text="Done 已完成", labelanchor="n")
        done_frame.pack(fill="both", expand=True)

        self.done_tree = ttk.Treeview(done_frame, show='headings', style="Done.Treeview")
        self.setup_tree_columns(self.done_tree, columns_done)
        self.done_tree.pack(fill="both", expand=True, padx=5, pady=5)

        delete_done_button = ttk.Button(done_frame, text="🗑️ 删除",
                                       command=lambda: self.delete_item(self.done_tree, self.done_items))
        delete_done_button.pack(pady=5)

        # 初始更新
        self.update_trees()

    def setup_tree_columns(self, tree, columns):
        """配置Treeview列"""
        tree["columns"] = tuple(columns)

        for col in columns:
            tree.heading(col, text=col)
            if col == "序号":
                tree.column(col, anchor="center", width=50)
            elif col == "内容":
                tree.column(col, anchor="w", width=150)
            elif col == "分类":
                tree.column(col, anchor="w", width=80)
            else:
                tree.column(col, anchor="w", width=80)

        tree.column("#0", width=0, stretch=tk.NO)
        tree.tag_configure('reminder', background='red', foreground='white')

    def get_task_values(self, task, status):
        """获取任务显示值，根据状态过滤字段"""
        values = []
        for col in self.get_tree_columns(status):
            if col == "序号":
                index = self.get_task_index(task, status)
                values.append(index + 1)
            elif col == "内容":
                values.append(task.content)
            elif col == "分类":
                values.append(task.tag)  # 添加分类信息
            elif col == "创建时间":
                values.append(task.created_at)
            elif col == "开始时间":
                values.append(task.started_at or "")
            elif col == "完成时间":
                values.append(task.done_at or "")

        return tuple(values)

    def get_tree_columns(self, status):
        """根据状态获取当前应该显示的列"""
        if status == "Todo":
            return ("序号", "内容", "分类", "创建时间")  # 添加分类列
        elif status == "Doing":
            return ("序号", "内容", "分类", "开始时间")  # 添加分类列
        else:  # Done
            return ("序号", "内容", "分类", "完成时间")  # 添加分类列

    def clear_tree(self, tree):
        for item in tree.get_children():
            tree.delete(item)

    def add_task(self, category="其他"):
        task = self.task_entry.get().strip()
        if task:
            self.todo_items.append(Task(task, tag=category))
            self.update_trees()
            self.task_entry.delete(0, tk.END)
        else:
            messagebox.showwarning("警告", "请输入一个任务！")

    def move_to_doing(self):
        selected = self.todo_tree.selection()
        if selected:
            index = self.todo_tree.index(selected[0])
            task = self.todo_items.pop(index)
            task.started_at = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
            # 清除提醒设置
            task.reminder_time = None
            task.daily_reminder = False
            task.reminder_active = False
            self.doing_items.append(task)
            self.update_trees()

    def move_to_done(self):
        selected = self.doing_tree.selection()
        if selected:
            index = self.doing_tree.index(selected[0])
            task = self.doing_items.pop(index)
            task.done_at = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
            self.done_items.append(task)
            self.update_trees()

    def delete_item(self, tree, items):
        selected = tree.selection()
        if selected:
            index = tree.index(selected[0])
            del items[index]
            self.update_trees()

    def load_tasks(self):
        if os.path.exists("tasks.json"):
            try:
                with open("tasks.json", "r") as f:
                    data = json.load(f)
                    self.todo_items = [Task.from_dict(t) for t in data.get("todo", [])]
                    self.doing_items = [Task.from_dict(t) for t in data.get("doing", [])]
                    self.done_items = [Task.from_dict(t) for t in data.get("done", [])]
            except Exception as e:
                messagebox.showerror("错误", f"加载任务失败: {str(e)}")

    def save_tasks(self):
        with open("tasks.json", "w") as f:
            json.dump({
                "todo": [t.to_dict() for t in self.todo_items],
                "doing": [t.to_dict() for t in self.doing_items],
                "done": [t.to_dict() for t in self.done_items]
            }, f)

    def export_to_excel(self):
        all_tasks = []
        for t in self.todo_items:
            d = t.to_dict()
            d['状态'] = 'Todo'
            all_tasks.append(d)
        for t in self.doing_items:
            d = t.to_dict()
            d['状态'] = 'Doing'
            all_tasks.append(d)
        for t in self.done_items:
            d = t.to_dict()
            d['状态'] = 'Done'
            all_tasks.append(d)

        if not all_tasks:
            messagebox.showwarning("警告", "没有任务可导出！")
            return

        try:
            df = pd.DataFrame(all_tasks)
            file_path = filedialog.asksaveasfilename(
                defaultextension=".xlsx", 
                filetypes=[("Excel 文件", "*.xlsx")],
                title="导出任务到Excel"
            )
            if file_path:  # 只有当用户选择了文件路径时才继续
                df.to_excel(file_path, index=False, engine='openpyxl')  # 指定engine为openpyxl
                messagebox.showinfo("成功", f"任务已导出至 {file_path}")
        except Exception as e:
            messagebox.showerror("错误", f"导出Excel失败: {str(e)}")

    def set_reminder(self):
        selected = self.todo_tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个任务设置提醒！")
            return

        index = self.todo_tree.index(selected[0])
        task = self.todo_items[index]

        reminder_window = tk.Toplevel(self.root)
        reminder_window.title("设置提醒")
        reminder_window.geometry("400x500")
        reminder_window.resizable(False, False)
        reminder_window.attributes('-topmost', True)
        
        # 使用自定义样式
        style = ttk.Style()
        style.configure("Reminder.TFrame", background="#f5f5f5")
        style.configure("Reminder.TLabel", font=("Arial", 10, "bold"))
        style.configure("Reminder.TButton", padding=5)

        # 主框架
        main_frame = ttk.Frame(reminder_window, style="Reminder.TFrame")
        main_frame.pack(fill="both", expand=True, padx=10, pady=10)

        # 提醒方式设置
        type_frame = ttk.LabelFrame(main_frame, text="提醒方式", padding=10)
        type_frame.pack(fill="x", pady=5)

        reminder_type = ttk.Combobox(type_frame, values=["单次提醒", "每日提醒"], state="readonly")
        # 修改：更精确地设置默认值
        if task.reminder_time:
            reminder_type.current(1 if task.daily_reminder else 0)
        else:
            reminder_type.current(0)  # 默认单次提醒
        reminder_type.pack(fill="x", pady=5)

        # 时间设置
        time_frame = ttk.LabelFrame(main_frame, text="提醒时间", padding=10)
        time_frame.pack(fill="x", pady=5)

        # 修改：更精确地获取时间
        if task.reminder_time:
            h, m = task.reminder_time.split(':')
        else:
            now = datetime.datetime.now()
            h = str(now.hour)
            m = str(now.minute)

        hour_frame = ttk.Frame(time_frame)
        hour_frame.pack(fill="x", pady=5)
        
        ttk.Label(hour_frame, text="时:").pack(side=tk.LEFT, padx=5)
        hour = ttk.Spinbox(hour_frame, from_=0, to=23, width=3)
        hour.set(h)
        hour.pack(side=tk.LEFT)
        
        minute_frame = ttk.Frame(time_frame)
        minute_frame.pack(fill="x", pady=5)
        
        ttk.Label(minute_frame, text="分:").pack(side=tk.LEFT, padx=5)
        minute = ttk.Spinbox(minute_frame, from_=0, to=59, width=3)
        minute.set(m)
        minute.pack(side=tk.LEFT)

        # 声音设置
        sound_frame = ttk.LabelFrame(main_frame, text="提醒声音", padding=10)
        sound_frame.pack(fill="x", pady=5)

        self.sound_entry = ttk.Entry(sound_frame, width=30)
        # 修改：直接使用task.sound_path作为默认值
        self.sound_entry.insert(0, task.sound_path if task.sound_path else "蜂鸣声")
        self.sound_entry.pack(pady=5)

        def select_sound_file():
            file_path = filedialog.askopenfilename(
                filetypes=[("音频文件", "*.wav *.mp3")],
                parent=reminder_window  # 指定父窗口
            )
            if file_path:
                self.sound_entry.delete(0, tk.END)
                self.sound_entry.insert(0, file_path)
                # 移除临时置顶属性
                reminder_window.attributes('-topmost', False)
                # 重新获得焦点
                reminder_window.focus_force()

        browse_frame = ttk.Frame(sound_frame)
        browse_frame.pack(fill="x", pady=5)
        
        ttk.Button(browse_frame, text="浏览...", command=select_sound_file).pack(side=tk.LEFT, padx=5)

        # 音频控制按钮
        control_frame = ttk.Frame(sound_frame)
        control_frame.pack(fill="x", pady=5)
        
        ttk.Button(control_frame, text="播放", command=lambda: self.play_sound(task.sound_path)).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="停止", command=self.stop_sound).pack(side=tk.LEFT, padx=5)

        # 操作按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill="x", pady=10)
        
        ttk.Button(button_frame, text="⏰ 设置提醒", command=lambda: self.schedule_reminder(reminder_window, task, reminder_type, hour, minute)).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="❌ 删除提醒", command=lambda: self.delete_reminder(reminder_window, task)).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="关闭", command=reminder_window.destroy).pack(side=tk.RIGHT)

    def schedule_reminder(self, window, task, reminder_type, hour, minute):
        """处理提醒设置逻辑"""
        rtype = reminder_type.get()
        h = hour.get()
        m = minute.get()
        time_str = f"{h.zfill(2)}:{m.zfill(2)}"
        task.reminder_time = time_str
        task.daily_reminder = (rtype == "每日提醒")
        task.reminder_active = True
        # 修改：确保正确保存声音路径
        sound_file = self.sound_entry.get()
        if sound_file and sound_file != "蜂鸣声" and os.path.exists(sound_file):
            task.sound_path = sound_file
        else:
            task.sound_path = None
        self.save_tasks()
        messagebox.showinfo("已设置", f"{task.content} 已设定{'每日' if task.daily_reminder else ''}提醒时间为 {time_str}")
        window.destroy()
        self.update_trees()

    def delete_reminder(self, window, task):
        """处理删除提醒逻辑"""
        task.reminder_time = None
        task.daily_reminder = False
        task.reminder_active = False
        task.sound_path = None  # 修改：确保清除sound_path
        self.stop_sound()
        self.save_tasks()
        messagebox.showinfo("已删除", "任务提醒已删除。")
        window.destroy()
        self.update_trees()

    def check_reminders(self):
        now = datetime.datetime.now().strftime("%H:%M")
        current_date = datetime.datetime.now().strftime("%Y-%m-%d")

        for task in self.todo_items + self.doing_items + self.done_items:
            if task.reminder_time and task.reminder_active and task.reminder_time == now:
                if task.daily_reminder or task.created_at == current_date:
                    # 使用线程播放音频避免界面卡住
                    def play_notification():
                        notification.notify(title="任务提醒", message=task.content)
                        # 查找并闪烁对应的Treeview项目
                        tree = None
                        if task in self.todo_items:
                            tree = self.todo_tree
                            index = self.todo_items.index(task)
                        elif task in self.doing_items:
                            tree = self.doing_tree
                            index = self.doing_items.index(task)
                        elif task in self.done_items:
                            tree = self.done_tree
                            index = self.done_items.index(task)
                        
                        if tree:
                            item_id = tree.get_children()[index]
                            self.flash_item(tree, item_id)
                        
                        try:
                            if task.sound_path and task.sound_path != "蜂鸣声" and os.path.exists(task.sound_path):
                                winsound.PlaySound(task.sound_path, winsound.SND_FILENAME | winsound.SND_ASYNC)
                            else:
                                self.start_buzzer()
                        except Exception as e:
                            print(f"播放音频失败: {e}")
                            self.start_buzzer()
                    
                    threading.Thread(target=play_notification, daemon=True).start()

        self.root.after(60000, self.check_reminders)  # 每分钟检查一次

    def flash_item(self, tree, item_id):
        """闪烁指定的Treeview项目"""
        self.current_flashing_item = (tree, item_id)
        # 修改：使用标签而不是直接设置背景色
        if not tree.tag_configure('flashing'):
            tree.tag_configure('flashing', background='#FF0000', foreground='white')
        
        def toggle():
            if not hasattr(self, 'current_flashing_item') or self.current_flashing_item != (tree, item_id):
                return
            
            current_tags = tree.item(item_id, 'tags')
            if 'flashing' in current_tags:
                tree.item(item_id, tags=tuple(t for t in current_tags if t != 'flashing'))
            else:
                tree.item(item_id, tags=current_tags + ('flashing',))
            
            self.root.after(500, toggle)  # 每500ms切换一次
    
        toggle()

    def play_sound(self, sound_file=None):
        """播放音频文件或默认蜂鸣声"""
        self.stop_sound()  # 先停止当前播放的声音
        
        if sound_file and sound_file != "蜂鸣声" and os.path.exists(sound_file):
            try:
                winsound.PlaySound(sound_file, winsound.SND_FILENAME | winsound.SND_ASYNC)
                return True
            except Exception as e:
                print(f"播放音频文件失败: {e}")
                self.start_buzzer()
                return False
        else:
            self.start_buzzer()
            return False

    def stop_sound(self):
        """停止所有声音"""
        self.stop_buzzer()
        try:
            winsound.PlaySound(None, winsound.SND_PURGE)
        except:
            pass
        # 清除闪烁状态
        if hasattr(self, 'current_flashing_item'):
            del self.current_flashing_item

    def start_buzzer(self):
        """启动蜂鸣器声音"""
        if not self.buzzer_active:
            self.buzzer_active = True
            self.buzzer_thread = threading.Thread(target=self._buzzer_loop, daemon=True)
            self.buzzer_thread.start()

    def stop_buzzer(self):
        """停止蜂鸣器声音"""
        self.buzzer_active = False
        if self.buzzer_thread and self.buzzer_thread.is_alive():
            self.buzzer_thread.join(timeout=0.1)
        self.buzzer_thread = None

    def _buzzer_loop(self):
        """蜂鸣器循环播放"""
        while self.buzzer_active:
            try:
                winsound.Beep(1000, 500)
                time.sleep(0.5)
            except:
                break

    def manage_tags(self):
        tag_window = tk.Toplevel(self.root)
        tag_window.title("管理分类")
        tag_window.geometry("300x300")
        tag_window.resizable(False, False)

        list_frame = ttk.Frame(tag_window)
        list_frame.pack(pady=10, fill="both", expand=True)

        tag_list = tk.Listbox(list_frame, selectmode=tk.SINGLE)
        tag_list.pack(side="left", fill="both", expand=True)

        scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=tag_list.yview)
        scrollbar.pack(side="right", fill="y")

        tag_list.config(yscrollcommand=scrollbar.set)

        for tag in TAG_CATEGORIES:
            tag_list.insert(tk.END, tag)

        btn_frame = ttk.Frame(tag_window)
        btn_frame.pack(pady=5, fill="x")

        new_tag = tk.StringVar()
        entry = ttk.Entry(btn_frame, textvariable=new_tag, width=15)
        entry.pack(side="left", padx=5)

        def add_tag():
            tag = new_tag.get().strip()
            if tag and tag not in TAG_CATEGORIES:
                TAG_CATEGORIES.append(tag)
                tag_list.insert(tk.END, tag)
                new_tag.set("")

        def remove_tag():
            selected = tag_list.curselection()
            if selected:
                tag = tag_list.get(selected[0])
                if tag in ["工作", "生活", "学习", "其他"]:
                    messagebox.showwarning("警告", "默认分类不能删除！")
                    return
                TAG_CATEGORIES.remove(tag)
                tag_list.delete(selected)

        ttk.Button(btn_frame, text="➕ 添加", command=add_tag).pack(side="left", padx=2)
        ttk.Button(btn_frame, text="❌ 删除", command=remove_tag).pack(side="left", padx=2)

        # 激活/禁用标签
        toggle_frame = ttk.Frame(tag_window)
        toggle_frame.pack(pady=5, fill="x")

        self.tag_states = {tag: tk.BooleanVar(value=True) for tag in TAG_CATEGORIES}

        for tag in TAG_CATEGORIES:
            cb = ttk.Checkbutton(toggle_frame, text=f"启用 {tag}", variable=self.tag_states[tag])
            cb.pack(anchor="w")

        ttk.Button(tag_window, text="保存并关闭", command=lambda: (self.save_tags(), tag_window.destroy())).pack(pady=10)

    def save_tags(self):
        # 可选：持久化保存分类信息
        pass

    def get_task_index(self, task, status):
        if status == "Todo":
            return self.todo_items.index(task)
        elif status == "Doing":
            return self.doing_items.index(task)
        elif status == "Done":
            return self.done_items.index(task)
        return -1

    def on_entry_click(self, event):
        """处理输入框获得焦点事件"""
        if self.task_entry.get() == "在此输入事务":
            self.task_entry.delete(0, tk.END)
            self.task_entry.config(foreground="black")  # 恢复正常字体颜色

    def on_focus_out(self, event):
        """处理输入框失去焦点事件"""
        if not self.task_entry.get():
            self.task_entry.insert(0, "在此输入事务")
            self.task_entry.config(foreground="grey")  # 提示文字使用灰色

    def update_trees(self):
        """更新所有Treeview显示"""
        # 清空现有数据
        self.clear_tree(self.todo_tree)
        self.clear_tree(self.doing_tree)
        self.clear_tree(self.done_tree)
        
        # 配置字体样式
        bold_font = ('Microsoft YaHei', 10, 'bold')
        normal_font = ('Microsoft YaHei', 10)
        
        # 配置特殊样式：有备注且设置了提醒的任务
        self.todo_tree.tag_configure('reminder_with_notes', 
                                   background='#FFF2CC',
                                   font=bold_font)
        self.doing_tree.tag_configure('reminder_with_notes', 
                                    background='#FFF2CC',
                                    font=bold_font)
        self.done_tree.tag_configure('reminder_with_notes', 
                                   background='#FFF2CC',
                                   font=bold_font)
        
        # 填充Todo列表
        for i, task in enumerate(self.todo_items):
            values = self.get_task_values(task, "Todo")
            item = self.todo_tree.insert("", tk.END, values=values)
            if task.notes and task.reminder_time and task.reminder_active:  # 有备注且设置了提醒
                self.todo_tree.item(item, tags=('reminder_with_notes',))
            elif task.notes:  # 只有备注
                self.todo_tree.tag_configure('has_notes', font=bold_font)
                self.todo_tree.item(item, tags=('has_notes',))
            elif task.reminder_time and task.reminder_active:  # 只有提醒
                self.todo_tree.item(item, tags=('reminder',))
        
        # 填充Doing列表
        for i, task in enumerate(self.doing_items):
            values = self.get_task_values(task, "Doing")
            item = self.doing_tree.insert("", tk.END, values=values)
            if task.notes and task.reminder_time and task.reminder_active:
                self.doing_tree.item(item, tags=('reminder_with_notes',))
            elif task.notes:
                self.doing_tree.tag_configure('has_notes', font=bold_font)
                self.doing_tree.item(item, tags=('has_notes',))
            elif task.reminder_time and task.reminder_active:
                self.doing_tree.item(item, tags=('reminder',))
        
        # 填充Done列表
        for i, task in enumerate(self.done_items):
            values = self.get_task_values(task, "Done")
            item = self.done_tree.insert("", tk.END, values=values)
            if task.notes and task.reminder_time and task.reminder_active:
                self.done_tree.item(item, tags=('reminder_with_notes',))
            elif task.notes:
                self.done_tree.tag_configure('has_notes', font=bold_font)
                self.done_tree.item(item, tags=('has_notes',))
            elif task.reminder_time and task.reminder_active:
                self.done_tree.item(item, tags=('reminder',))
        
        # 保存更新
        self.save_tasks()

    def show_guide(self):
        """显示使用指南对话框"""
        guide_window = tk.Toplevel(self.root)
        guide_window.title("使用指南")
        guide_window.geometry("600x500")  # 增大窗口尺寸以适应更多内容
        guide_window.resizable(False, False)
        
        text = tk.Text(guide_window, wrap="word", padx=10, pady=10)
        text.pack(fill="both", expand=True)
        
        guide_text = """
        TickTick 任务管理使用指南
        
        1. 基本功能
        - 添加任务: 在输入框中输入任务内容，选择分类后点击"添加"按钮
        - 状态管理:
          * 待办(Todo): 新添加的任务
          * 进行中(Doing): 双击任务或点击"▶️ 开始"按钮
          * 已完成(Done): 双击任务或点击"✅ 完成"按钮
        
        2. 提醒功能
        - 设置提醒: 双击待办任务可设置提醒
          * 可选择单次提醒或每日提醒
          * 可自定义提醒声音
        - 提醒效果:
          * 提醒时会播放声音
          * 对应的任务项会闪烁显示以便识别
          * 点击"停止"按钮可同时停止声音和闪烁
        
        3. 任务备注
        - 右键点击任务选择"添加备注"
        - 备注支持多行文本(最多300字)
        - 有备注的任务会以粗体显示
        - 有备注且设置了提醒的任务会有特殊高亮
        
        4. 任务编辑
        - 右键点击任务可编辑内容或分类
        - 右键菜单也支持删除任务
        
        5. 分类管理
        - 在"配置"菜单中可管理任务分类
        - 可以添加、删除和启用/禁用分类
        
        6. 数据导入导出
        - 在"文件"菜单中可导出任务到Excel
        - 支持从Excel导入任务
        
        7. 其他提示
        - 任务列表支持右键快捷操作
        - 输入框有智能清空和恢复提示功能
        - 界面会自动保存所有更改
        """
        text.insert("1.0", guide_text)
        text.config(state="disabled")  # 设置为只读
        
        ttk.Button(guide_window, text="关闭", command=guide_window.destroy).pack(pady=10)

    def show_about(self):
        """显示关于对话框"""
        about_window = tk.Toplevel(self.root)
        about_window.title("关于 TickTick")
        about_window.geometry("300x200")
        about_window.resizable(False, False)
        
        ttk.Label(about_window, text="TickTick 事务管理", font=("Arial", 14, "bold")).pack(pady=10)
        ttk.Label(about_window, text="版本: 1.0.0").pack()
        ttk.Label(about_window, text="开发团队: 人工智能技术团队").pack(pady=10)
        ttk.Label(about_window, text="© 2025 北京富通昌进出口有限公司版权所有").pack()
        
        ttk.Button(about_window, text="确定", command=about_window.destroy).pack(pady=10)

    def show_context_menu(self, event):
        """显示右键上下文菜单"""
        tree = event.widget
        selected_item = tree.identify_row(event.y)
        
        if selected_item:  # 确保选中了项目
            tree.selection_set(selected_item)
            
            # 创建菜单
            menu = tk.Menu(self.root, tearoff=0)
            
            # 根据Treeview类型添加不同菜单项
            if tree == self.todo_tree:
                menu.add_command(label="编辑任务", command=lambda: self.edit_selected_task(self.todo_tree, self.todo_items))
                menu.add_command(label="添加备注", command=lambda: self.edit_notes(self.todo_tree, self.todo_items))
            elif tree == self.doing_tree:
                menu.add_command(label="编辑任务", command=lambda: self.edit_selected_task(self.doing_tree, self.doing_items))
                menu.add_command(label="添加备注", command=lambda: self.edit_notes(self.doing_tree, self.doing_items))
            else:  # Done tree
                menu.add_command(label="编辑任务", command=lambda: self.edit_selected_task(self.done_tree, self.done_items))
                menu.add_command(label="添加备注", command=lambda: self.edit_notes(self.done_tree, self.done_items))
            
            # 显示菜单
            menu.post(event.x_root, event.y_root)

    def edit_notes(self, tree, items):
        """编辑任务的备注"""
        selected = tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个任务进行备注！")
            return
            
        index = tree.index(selected[0])
        task = items[index]
        
        # 创建备注编辑窗口
        notes_window = tk.Toplevel(self.root)
        notes_window.title(f"任务备注 - {task.content}")
        notes_window.geometry("600x450")
        notes_window.resizable(True, True)
        
        # 主框架
        main_frame = ttk.Frame(notes_window)
        main_frame.pack(fill="both", expand=True, padx=10, pady=10)
        
        # 标题
        ttk.Label(main_frame, 
                text=f"任务: {task.content}", 
                font=('Microsoft YaHei', 12, 'bold')).pack(pady=(0, 10))
        
        # 备注内容框架
        content_frame = ttk.Frame(main_frame)
        content_frame.pack(fill="both", expand=True)
        
        # 使用Text组件支持多行输入，带滚动条
        text_frame = ttk.Frame(content_frame)
        text_frame.pack(fill="both", expand=True)
        
        notes_text = tk.Text(text_frame, 
                            wrap="word", 
                            height=15, 
                            width=60,
                            font=('Microsoft YaHei', 11),
                            padx=10,
                            pady=10)
        notes_text.insert("1.0", task.notes)
        notes_text.pack(side="left", fill="both", expand=True)
        
        scrollbar = ttk.Scrollbar(text_frame, command=notes_text.yview)
        scrollbar.pack(side="right", fill="y")
        notes_text.config(yscrollcommand=scrollbar.set)
        
        # 字数统计
        char_count = tk.StringVar()
        char_count.set(f"字数: {len(task.notes)}/300 (剩余{300-len(task.notes)})")
        count_frame = ttk.Frame(main_frame)
        count_frame.pack(fill="x", pady=(5, 0))
        
        ttk.Label(count_frame, 
                 textvariable=char_count,
                 font=('Microsoft YaHei', 9)).pack(side="left")
        
        def update_count(event=None):
            """更新字数统计"""
            content = notes_text.get("1.0", "end-1c")
            remaining = 300 - len(content)
            char_count.set(f"字数: {len(content)}/300 (剩余{remaining})")
            if len(content) > 300:
                char_count.set(f"字数: {len(content)}/300 (超出{len(content)-300})")
            
        notes_text.bind("<KeyRelease>", update_count)
        
        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill="x", pady=(10, 0))
        
        def save_notes():
            content = notes_text.get("1.0", "end-1c")
            if len(content) > 300:
                messagebox.showwarning("警告", "备注内容不能超过300字！")
                return
            task.notes = content
            self.save_tasks()
            notes_window.destroy()
            self.update_trees()  # 更新显示以反映粗体变化
            messagebox.showinfo("成功", "备注已保存！")
            
        ttk.Button(button_frame, 
                  text="保存", 
                  style="Accent.TButton",
                  command=save_notes).pack(side="right", padx=5)
        ttk.Button(button_frame, 
                  text="取消", 
                  command=notes_window.destroy).pack(side="right")
        
        # 初始焦点和窗口行为
        notes_text.focus_set()
        notes_window.transient(self.root)
        notes_window.grab_set()

    def edit_selected_task(self, tree, items):
        """编辑选中的任务"""
        selected = tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个任务进行编辑！")
            return
            
        index = tree.index(selected[0])
        task = items[index]
        
        # 创建编辑窗口
        edit_window = tk.Toplevel(self.root)
        edit_window.title("编辑任务")
        edit_window.geometry("400x300")
        
        # 任务内容
        ttk.Label(edit_window, text="任务内容:").pack(pady=(10, 0))
        content_entry = ttk.Entry(edit_window, width=40)
        content_entry.insert(0, task.content)
        content_entry.pack(pady=5)
        
        # 分类选择
        ttk.Label(edit_window, text="分类:").pack()
        category_var = tk.StringVar(value=task.tag)
        category_menu = ttk.Combobox(
            edit_window,
            textvariable=category_var,
            values=TAG_CATEGORIES,
            state="readonly",
            width=15
        )
        category_menu.pack(pady=5)
        
        # 保存按钮
        def save_changes():
            task.content = content_entry.get().strip()
            task.tag = category_var.get()
            self.update_trees()
            edit_window.destroy()
            messagebox.showinfo("成功", "任务已更新！")
            
        ttk.Button(edit_window, text="保存", command=save_changes).pack(pady=15)

    def delete_selected_task(self, tree, items):
        """删除选中的任务"""
        selected = tree.selection()
        if selected:
            if messagebox.askyesno("确认", "确定要删除这个任务吗？"):
                index = tree.index(selected[0])
                del items[index]
                self.update_trees()

    def import_from_excel(self):
        """从Excel文件导入任务"""
        try:
            file_path = filedialog.askopenfilename(
                filetypes=[("Excel 文件", "*.xlsx *.xls")],
                title="选择要导入的Excel文件"
            )
            if not file_path:
                return

            # 读取Excel文件
            df = pd.read_excel(file_path, engine='openpyxl')
            
            # 检查必要的列是否存在
            required_columns = ['内容', '分类', '创建时间', '状态']
            if not all(col in df.columns for col in required_columns):
                messagebox.showerror("错误", "Excel文件缺少必要的列！")
                return

            # 清空现有任务
            self.todo_items = []
            self.doing_items = []
            self.done_items = []

            # 处理每一行数据
            for _, row in df.iterrows():
                task = Task(
                    content=row['内容'],
                    tag=row.get('分类', '其他'),
                    created_at=row.get('创建时间')
                )
                
                # 设置任务状态
                status = row.get('状态', 'Todo')
                if status == 'Todo':
                    self.todo_items.append(task)
                elif status == 'Doing':
                    task.started_at = row.get('开始时间', datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
                    self.doing_items.append(task)
                elif status == 'Done':
                    task.done_at = row.get('完成时间', datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
                    self.done_items.append(task)

                # 设置提醒信息
                if '提醒时间' in df.columns and pd.notna(row['提醒时间']):
                    task.reminder_time = row['提醒时间']
                    task.daily_reminder = row.get('每日提醒', False)
                    task.reminder_active = row.get('提醒状态', True)
                    task.sound_path = row.get('声音路径')

            # 更新界面并保存
            self.update_trees()
            self.save_tasks()
            messagebox.showinfo("成功", "任务已从Excel导入！")

        except Exception as e:
            messagebox.showerror("错误", f"导入Excel失败: {str(e)}")

if __name__ == "__main__":
    root = tk.Tk()
    try:
        root.iconbitmap("app.ico")
    except tk.TclError:
        print("图标文件加载失败，请确保 app.ico 存在且格式正确")

    app = TodoApp(root)
    root.mainloop()